

#include "a.h" 

#include "System.h"
#include "EquationSystem.h"
#include "GetPot"

#include<iostream>
using namespace std;

#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/Error.h>

#include "Parameter.h"
#include "CommandLine.h"
#include "Initialize.h"
#include "Application.h"
#include "Factory.h"
#include "GeneratedMesh.h"

#include <petscksp.h>

static const vtkm::cont::LogLevel CustomLogLevel = vtkm::cont::LogLevel::Cast;
#define SIZE 3

int main(int argc, char** argv)
{
	GeneratedMesh<3> mesh;
	mesh.build();

	mesh.PrintSummary(std::cout);

	Vec x, b;   /* approx solution, rhs */
	Mat A;     /* linear system matrix */
	KSP ksp;   /* linear solver context */
	PC pc;     /* preconditioner context */
	int size;
	PetscInt col[3], i;
	PetscScalar temp[SIZE];

	PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
	MPI_Comm_size(PETSC_COMM_WORLD, &size);
	if (size != 1) PetscPrintf(PETSC_COMM_WORLD, "warning, %d threads\n", size);
	/* create vectors */
	VecCreate(PETSC_COMM_WORLD, &x);
	VecSetSizes(x, PETSC_DECIDE, SIZE);
	VecSetFromOptions(x);
	VecDuplicate(x, &b);



	temp[0] = 14.5; temp[1] = 54; temp[2] = 0.423;
	for (i = 0; i < 3; i++) VecSetValues(b, 1, &i, &temp[i], INSERT_VALUES);

	PetscScalar* pp;
	VecGetArray(b, &pp);
	PetscInt size_b;
	VecGetSize(b, &size_b);
	auto bb = vtkm::cont::make_ArrayHandle(pp, size_b);

	for (size_t i = 0; i < bb.GetNumberOfValues(); i++)
	{
		std::cout << bb.ReadPortal().Get(i) << std::endl;
	}

	VecSetValue(b, 2, 100, INSERT_VALUES);


	for (size_t i = 0; i < bb.GetNumberOfValues(); i++)
	{
		std::cout << bb.ReadPortal().Get(i) << std::endl;
		bb.WritePortal().Set(i, i + 1);
	}

	Vec rhs;
	VecCreate(PETSC_COMM_WORLD, &rhs);
	VecSetSizes(rhs, PETSC_DECIDE, 10);
	VecSetFromOptions(rhs);
	PetscScalar* p_rhs;
	//VecGetArray(rhs, &p_rhs);
	VecGetSize(rhs, &size_b);

	std::cout << size_b;
	//VecView(rhs, PETSC_VIEWER_STDOUT_WORLD);
	ArrayHandle<PetscScalar> vtkm_rhs;

	/* need to assemble after setting values! do necessary
	   message passing etc to propagate matrix to all ranks */
	VecAssemblyBegin(b);
	VecAssemblyEnd(b);
	/* create matrix */
	MatCreate(PETSC_COMM_WORLD, &A);
	MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, SIZE, SIZE);
	MatSetFromOptions(A);
	MatSetUp(A);
	temp[0] = 1; temp[1] = 1; temp[2] = 1;
	col[0] = 0; col[1] = 1; col[2] = 2;
	for (i = 0; i < 3; i++) {
		MatSetValues(A, 1, &i, 3, col, temp, INSERT_VALUES);
		temp[i] = 0;
	}
	/* need to assemble matrix for the same reasons as above */
	MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
	MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
	/* linear solver context! */
	KSPCreate(PETSC_COMM_WORLD, &ksp);
	/* operator is A matrix, also set matrix for preconditioning here */
	KSPSetOperators(ksp, A, A);
	/* get pc context from ksp context */
	KSPGetPC(ksp, &pc);
	/* set preconditioner type */
	PCSetType(pc, PCJACOBI);
	KSPSetTolerances(ksp, 1e-6, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
	KSPSetFromOptions(ksp);
	/* solve! */
	KSPSolve(ksp, b, x);
	/* display everything */
	MatView(A, PETSC_VIEWER_STDOUT_WORLD);
	VecView(b, PETSC_VIEWER_STDOUT_WORLD);
	VecView(x, PETSC_VIEWER_STDOUT_WORLD);
	KSPView(ksp, PETSC_VIEWER_STDOUT_WORLD);
	/* get rid of everything */
	KSPDestroy(&ksp);
	VecDestroy(&x);
	VecDestroy(&b);
	PetscFinalize();


//    //GetPot      cl(argc, argv);      // command line args
//	vtkm::cont::SetStderrLogLevel(CustomLogLevel);
//	VTKM_LOG_S(vtkm::cont::LogLevel::Info, "info" << COR_VERSION_MAJOR_V2);
//	VTKM_LOG_S(vtkm::cont::LogLevel::MemCont, "ccc %d", 100);
//	VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Warn");
//	VTKM_LOG_S(vtkm::cont::LogLevel::Error, "Error" << 1);
//
//	try
//	{
//		throw vtkm::cont::ErrorBadValue("a");
//	}
//	catch (const vtkm::cont::Error & e)
//	{
//		VTKM_LOG_S(vtkm::cont::LogLevel::Error, e.GetStackTrace());
//	}
//	vtkm::cont::Initialize(argc, argv);
//	::Initialize(argc, argv);
//
//	//Application app;
//
//	Factory::instance().reg<Application>("app");
//
//	auto app = Factory::instance().createApp("app", argc, argv);
//
//	app->run();
//	Parameter param;
//	param.set<int>("a", 1234, "");
//	
//	int a = param.get<int>("a");
//
//    GetPot infile("../../../cfg.in");
//    const unsigned int n_iters = infile("n_iters", 2);
//	try
//	{
//		vtkm::cont::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterTagSerial{});
//		System system;
//		system.run(n_iters);
//	}
//	catch (const vtkm::cont::Error& e)
//	{
//		std::cout << e.GetMessage() << std::endl;
//		VTKM_LOG_S(CustomLogLevel, " Stack location : " << e.GetStackTrace());
//
//	}
}

